#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_set>

#include "Inet.hpp"
#include "Log.hpp"

using namespace log_ddsm;

const static std::string gpath = "./safe_com.txt";

class Command
{
private:
    void Load(const std::string &gpath)
    {
        // 打开文件
        std::ifstream in(gpath);
        if (!in.is_open())
        {
            LOG(FATAL, "open file fail!\n");
            exit(1);
        }
        std::string line;
        while (std::getline(in, line))
        {
            // 跳过空行
            if (line.empty())
                continue;
            // 插入
            _safe_comd.insert(line);

            LOG(DEBUG, "load %s success!\n", line.c_str());
        }

        in.close(); // 关闭文件
    }

public:
    Command()
        : _safe_comd()
    {
        // 想要使用的命令可以在构造函数添加
        // 通过配置文件添加
        // 这些命令就是白名单
        Load(gpath);
    }
    // 白名单检查
    bool SafeCheck(const std::string &comd)
    {
        if (_safe_comd.count(comd)) // 严格的检查，收到的命令必须必须完全相同才可以执行
        {
            return true;
        }
        return false;
    }
    // 黑名单检查
    bool UnsafeCheck(const std::string &comd)
    {
    }

    std::string Excute(const std::string &comd)
    {
        if (!SafeCheck(comd))
        {
            return "Unsafe,Permission Denied";
        }

        FILE *fp = popen(comd.c_str(), "r");
        if (fp)
        {
            std::string result;
            char line[MSSIZE] = {0};
            while (fgets(line, sizeof(line), fp))
            {
                result += line;
            }
            return result.empty() ? "success" : result;
        }
        return "Excute Error";
    }
    void CommandHelper(int rwfd, const Inet &peer)
    {
        // 长服务
        while (true)
        {
            char cmdmsg[MSSIZE] = {0}; // 缓冲区大小MSSIZE
            // 类似于read，只不过多一个参数
            ssize_t n = recv(rwfd, cmdmsg, sizeof(cmdmsg) - 1, 0);
            if (n > 0)
            {
                cmdmsg[n] = '\0';
                std::cout << "get message from " << "[" << peer.UniqueName().c_str() << "]" << cmdmsg << std::endl;
                std::string result = Excute(cmdmsg);
                // 类似于write，只不过多一个参数
                send(rwfd, result.c_str(), result.size(), 0);
            }
            else if (n == 0) // 代表客户端退出
            {
                LOG(INFO, "client [%s] quit/EOF\n", peer.UniqueName().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "client [%s] read fail!\n", peer.UniqueName().c_str());
                break;
            }
        }
        close(rwfd);
    }

    ~Command()
    {
    }

private:
    std::unordered_set<std::string> _safe_comd;   // 白名单
    std::unordered_set<std::string> _unsafe_comd; // 黑名单
};